
public class PLLayerFeature extends PLLayer {	
	PLFeature[][] mFeatures;
	protected PLMNDist mShapeDists;
	int mRows =0;
	int mCols = 0;

	public PLLayerFeature() {
	}
	
	public PLLayerFeature(String name) {	
		super(name);
		Init();
	}

	protected void finalize() throws Throwable
	{
		Shutdown();
	  //do finalization here
	  super.finalize(); //not necessary if extending Object.
	} 
		
	public boolean Init() {
		if (!InitDataFromFile()) 
			return false;
		return true;
	}

	public boolean Shutdown() {
		return SaveDataToFile();
	}
	
	// a layer may be asked to build a response to a query from scratch.
	// returns a new shape as a response and the confidence in this response
	public float BuildResponse(PLShape query, PLOutShape  outResponse) {
		if (!query.IsValid() || query.GetShapeId().getId() >= mShapeDists.GetSize()) 
			return 0f;

		PLDist dist = mShapeDists.GetDistributionAt(query.GetShapeId().getId());

		// pick a feature from the distribution
		int index = dist.PickIndex();

		if (index == -1 || index > mCols) {
			PLDebug.Warn("Dist at %d returned bad index %d", query.GetShapeId().getId(), index);
			return 0f;
		}

		// use the response where most patterns agree		
		float confidence = mFeatures[query.GetShapeId().getId()][index].BuildResponse(query, outResponse);

		return confidence;
	}	

	// given a query, response pair a layer may be asked to validate the response 
	// and possible return a better match if the confidence in the given response is not high
	public  float ValidateResponse(PLShape query, PLShape response, PLOutShape  outBetterMatch) {
		// use the response where most patterns agree		
		float confidence = 0;
		return confidence;
	}			


	// PRIVATE MEMBERS

	@Override
	public float ImproveResponse(PLShape query, PLOutShape outResponse, PLShape  betterMatch) {
		// TODO Auto-generated method stub
		return 0;
	}


	// inits the patterns from the file
	private boolean InitDataFromFile() {

		// first check if modified file exists, otherwise the base file
		String filename = PLFileUtils.GetModifiedFeatureFile(GetName());
		if (!PLFileUtils.Exists(filename)) {
			filename = PLFileUtils.GetFeatureFile(GetName());
			if (!PLFileUtils.Exists(filename)) {
				PLDebug.Err("Feature file does not exist");
				return false;
			}
		}

		// get the key value file name
		PLFileKeyValue<PLMNDist, PLFeature[][]> file = new PLFileKeyValue<PLMNDist, PLFeature[][]>(filename);
		file.BeginRead();

		// there must be one record in the file
		if (file.GetNumOfRecords() < 1) {
			return false;
		}
		
		PLRecordKeyValue<PLMNDist, PLFeature[][]> record = file.GetNextRecord();

		mShapeDists = record.GetKey();
		mFeatures = record.GetValue();

		
		
		if (mShapeDists == null || mFeatures == null) {
			PLDebug.Err("Record invalid!");
			return false;
		}	

		if (mShapeDists.GetSize() == 0 || mFeatures.length != mShapeDists.GetSize() ) {
			PLDebug.Err("Size Mismatc %d != %d", mShapeDists.GetSize(), mFeatures.length);
			return false;
		}

		mRows = mShapeDists.GetSize();
		mCols = mFeatures[0].length;
								
		// all done 	
		return true;
	}

	private boolean SaveDataToFile() {
		// write to modified file
		String filename = PLFileUtils.GetModifiedFeatureFile(GetName());

		PLRecordKeyValue<PLMNDist, PLFeature[][]> record = new PLRecordKeyValue<PLMNDist, PLFeature[][]>();

		record.Set(mShapeDists, mFeatures);		
				
		// get the key value file name
		PLFileKeyValue<PLMNDist, PLFeature[][]> file = new PLFileKeyValue<PLMNDist, PLFeature[][]>(filename);
		file.WriteRecord(record);

		// just one record to write, we are all done
		file.FinishedWriting();
												
		// all done 	
		return true;
	}
}
